package com.quectel.mobile.controller.invoice;

import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.constant.core.invoice.InvoiceConstants;
import com.quectel.constant.core.parking.ParkingOrderConstants;
import com.quectel.constant.core.parkingcard.ParkingCardOrderConstants;
import com.quectel.constant.core.propertybill.PropertyBillConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.household.dto.HouseholdDto;
import com.quectel.core.module.invoice.dto.InvoiceDto;
import com.quectel.core.module.invoice.dto.InvoiceItemDto;
import com.quectel.core.module.invoice.dto.InvoiceTitleDto;
import com.quectel.core.module.invoice.service.InvoiceItemService;
import com.quectel.core.module.invoice.service.InvoiceService;
import com.quectel.core.module.invoice.service.InvoiceTitleService;
import com.quectel.core.module.parking.dto.ParkingOrderDto;
import com.quectel.core.module.parking.service.ParkingOrderService;
import com.quectel.core.module.parkingcard.dto.ParkingCardOrderDto;
import com.quectel.core.module.parkingcard.service.ParkingCardOrderService;
import com.quectel.core.module.propertybill.dto.PropertyBillDto;
import com.quectel.core.module.propertybill.service.PropertyBillService;
import com.quectel.mobile.controller.BaseController;
import com.quectel.mobile.util.SessionHolder;
import com.quectel.mobile.vo.invoice.InvoiceSubmitVo;
import com.quectel.util.common.Page;
import com.quectel.util.common.Request;
import com.quectel.util.common.Response;
import com.quectel.util.ex.CheckErrorException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author zhangheng
 * @email nolan.zhang@quectel.com
 * @date 2023/4/21 10:56
 * @description new java file header...
 */
@RestController
@RequestMapping("invoice")
@Slf4j
@Tag(name = "InvoiceController", description = "Mobile端-住户开票记录相关api")
public class InvoiceController extends BaseController {

    @DubboReference
    private InvoiceService invoiceService;
    @DubboReference
    private InvoiceItemService invoiceItemService;
    @DubboReference
    private InvoiceTitleService invoiceTitleService;
    @DubboReference
    private PropertyBillService propertyBillService;
    @DubboReference
    private ParkingCardOrderService parkingCardOrderService;
    @DubboReference
    private ParkingOrderService parkingOrderService;



    @GetMapping("getInvoicePdf")
    @Operation(summary = "通过开票记录id,获取发票pdf文件")
    public Response<Object> getInvoicePdf(Long invoiceId) {
        SessionHolder.checkMobileUser();
        SessionHolder.checkHousehold();

        HouseholdDto currentHousehold = SessionHolder.getLoginMobileUserSession().getCurrentHousehold();

        Map<String, Object> params = new HashMap<>();
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(invoiceId));
        params.put(LambdaUtil.getFieldName(InvoiceDto::getTenantId), String.valueOf(currentHousehold.getTenantId()));
        params.put(LambdaUtil.getFieldName(InvoiceDto::getVillageId), String.valueOf(currentHousehold.getVillageId()));
        params.put(LambdaUtil.getFieldName(InvoiceDto::getPersonType), InvoiceConstants.PersonSourceTypeEnum.HOUSEHOLD.getPersonSourceType());
        params.put(LambdaUtil.getFieldName(InvoiceDto::getPersonId), String.valueOf(currentHousehold.getId()));
        if (invoiceService.queryTotal(params) <= 0) {
            return Response.error("未查询到开票记录");
        }
        InvoiceDto invoiceDto = invoiceService.selectById(invoiceId);
        if (invoiceDto == null) {
            return Response.error("未查询到开票记录");
        }
        //返回开票上传的附件
        String extFiles = invoiceDto.getExtFiles();
        return Response.ok().wrap(extFiles);
    }


    /**
     * 查看详情
     *
     * @param id
     * @return
     */
    @GetMapping("info/{id}")
    @Operation(summary = "查询详情")
    public Response<InvoiceDto> info(@PathVariable("id") Long id) {
        SessionHolder.checkMobileUser();
        SessionHolder.checkHousehold();

        HouseholdDto currentHousehold = SessionHolder.getLoginMobileUserSession().getCurrentHousehold();

        Map<String, Object> params = new HashMap<>();
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        params.put(LambdaUtil.getFieldName(InvoiceDto::getTenantId), String.valueOf(currentHousehold.getTenantId()));
        params.put(LambdaUtil.getFieldName(InvoiceDto::getVillageId), String.valueOf(currentHousehold.getVillageId()));
        params.put(LambdaUtil.getFieldName(InvoiceDto::getPersonType), InvoiceConstants.PersonSourceTypeEnum.HOUSEHOLD.getPersonSourceType());
        params.put(LambdaUtil.getFieldName(InvoiceDto::getPersonId), String.valueOf(currentHousehold.getId()));
        if (invoiceService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        InvoiceDto commonInvoiceDto = invoiceService.selectById(id);

        return Response.<InvoiceDto>ok().wrap(commonInvoiceDto);
    }

    /**
     * 获取开票列表
     *
     * @param sourceType
     * @return
     */
    @GetMapping("list")
    @Operation(summary = "获取开票记录")
    public Response<Page<InvoiceDto>> list(@Parameter(description = "开票类型1.物业费 2.临停费 3.停车月卡") Byte sourceType) {
        SessionHolder.checkMobileUser();
        SessionHolder.checkHousehold();
        HouseholdDto currentHousehold = SessionHolder.getLoginMobileUserSession().getCurrentHousehold();

        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        request.put(LambdaUtil.getFieldName(InvoiceDto::getTenantId), String.valueOf(currentHousehold.getTenantId()));
        request.put(LambdaUtil.getFieldName(InvoiceDto::getSourceType), sourceType);
        request.put(LambdaUtil.getFieldName(InvoiceDto::getPersonType), InvoiceConstants.PersonSourceTypeEnum.HOUSEHOLD.getPersonSourceType());
        request.put(LambdaUtil.getFieldName(InvoiceDto::getPersonId), String.valueOf(currentHousehold.getId()));

        int total = invoiceService.queryTotal(request.getParams());

        List<InvoiceDto> list = null;
        if (total > 0) {
            list = invoiceService.queryList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        Page<InvoiceDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<InvoiceDto>>ok().wrap(page);

    }

    /**
     * 申请开票
     * 1.校验数据，提交数据以及所选开票订单的开票状态
     * 2.组装数据 开票记录 主表 和 副表数据
     * 3.保存主副表数据，
     * 4.更新所开的对应类型的订单的开票状态，
     * 如我开的会议室订单,则更新选择的会议室那几条记录的开票状态
     * 5.具体开票操作，
     *   todo 调用开票接口
     *
     * @param invoiceSubmitVo
     * @return
     */
    @PostMapping("submit")
    @Operation(summary = "提交开票申请")
    public Response<Object> submit(@RequestBody InvoiceSubmitVo invoiceSubmitVo) {
        SessionHolder.checkMobileUser();
        SessionHolder.checkHousehold();
        HouseholdDto currentHousehold = SessionHolder.getLoginMobileUserSession().getCurrentHousehold();

        Long invoiceTitleId = invoiceSubmitVo.getInvoiceTitleId();
        if (invoiceTitleId == null) {
            return Response.error("开票抬头信息不能为空");
        }

        InvoiceTitleDto invoiceTitleDto = invoiceTitleService.selectById(invoiceTitleId);

        List<Long> invoiceOrderVoList =
                invoiceSubmitVo.getInvoiceOrderVoList();
        if (CollectionUtils.isEmpty(invoiceOrderVoList)) {
            return Response.error("开票帐单不能为空");
        }

        String invoiceContent = null;
        // 校验状态开票订单状态
        BigDecimal billTotal = BigDecimal.ZERO;
        List<InvoiceItemDto> invoiceItemList = new ArrayList<>();
        //TODO 待优化

        // 物业费账单
        if (invoiceSubmitVo.getSourceType().equals(InvoiceConstants.InvoiceItemSourceType.PROPERTY_BILL.getType())) {
            invoiceContent = InvoiceConstants.InvoiceItemSourceType.PROPERTY_BILL.getDesc();
            // 校验账单 组装关联表账单数据
            for (Long billId : invoiceOrderVoList) {
                PropertyBillDto propertyBillDto = propertyBillService.selectById(billId);
                //订单未开票并且订单是已支付状态
                if (propertyBillDto != null
                        && propertyBillDto.getInvoiceStatus().equals(InvoiceConstants.InvoiceStatus.NOT_SUBMITTED.getType())
                        && propertyBillDto.getPayStatus().equals(PropertyBillConstants.PayStatus.PAY_SUCCESS.getStatusValue())) {

                    billTotal = propertyBillDto.getTotalAmount().add(billTotal);
                    InvoiceItemDto recordDto = new InvoiceItemDto();
                    recordDto.setSourceType(invoiceSubmitVo.getSourceType());
                    recordDto.setSourceId(propertyBillDto.getId());
                    invoiceItemList.add(recordDto);
                } else {
                    return Response.error(SystemConstants.ILLEGAL_MSG);
                }
            }

        }

        // 停车账单
        if (invoiceSubmitVo.getSourceType().equals(InvoiceConstants.InvoiceItemSourceType.PARKING_BIll.getType())) {
            invoiceContent = InvoiceConstants.InvoiceItemSourceType.PARKING_BIll.getDesc();
            // 校验账单 组装关联表账单数据
            for (Long billId : invoiceOrderVoList) {
                ParkingOrderDto parkingOrderDto = parkingOrderService.selectById(billId);
                //订单未开票并且订单是已支付状态
                if (parkingOrderDto != null
                        && parkingOrderDto.getInvoiceStatus().equals(InvoiceConstants.InvoiceStatus.NOT_SUBMITTED.getType())
                        && parkingOrderDto.getPayStatus().equals(ParkingOrderConstants.OrderPayStatusEnum.PAY_SUCCESS.getPayStatus())) {

                    billTotal = parkingOrderDto.getPayAmount().add(billTotal);
                    InvoiceItemDto recordDto = new InvoiceItemDto();
                    recordDto.setSourceType(invoiceSubmitVo.getSourceType());
                    recordDto.setSourceId(parkingOrderDto.getId());
                    invoiceItemList.add(recordDto);
                } else {
                    return Response.error(SystemConstants.ILLEGAL_MSG);
                }
            }

        }

        // 月卡账单
        if (invoiceSubmitVo.getSourceType().equals(InvoiceConstants.InvoiceItemSourceType.PARKING_CARD.getType())) {
            invoiceContent = InvoiceConstants.InvoiceItemSourceType.PARKING_CARD.getDesc();
            // 校验账单 组装关联表账单数据
            for (Long billId : invoiceOrderVoList) {
                ParkingCardOrderDto parkingCardOrderDto = parkingCardOrderService.selectById(billId);
                //订单未开票并且订单是已支付状态
                if (parkingCardOrderDto != null
                        && parkingCardOrderDto.getInvoiceStatus().equals(InvoiceConstants.InvoiceStatus.NOT_SUBMITTED.getType())
                        && parkingCardOrderDto.getPayStatus().equals(ParkingCardOrderConstants.OrderPayStatusEnum.PAY_SUCCESS.getPayStatus())) {

                    billTotal = parkingCardOrderDto.getPayAmount().add(billTotal);
                    InvoiceItemDto recordDto = new InvoiceItemDto();
                    recordDto.setSourceType(invoiceSubmitVo.getSourceType());
                    recordDto.setSourceId(parkingCardOrderDto.getId());
                    invoiceItemList.add(recordDto);
                } else {
                    return Response.error(SystemConstants.ILLEGAL_MSG);
                }
            }

        }


        logger.debug("账单金额：{}", billTotal);
        // 主数据组装
        InvoiceDto invoiceDto = new InvoiceDto();
        invoiceDto.setTenantId(currentHousehold.getTenantId());
        invoiceDto.setVillageId(currentHousehold.getVillageId());
        invoiceDto.setSourceType(invoiceSubmitVo.getSourceType());
        invoiceDto.setPersonType(InvoiceConstants.PersonSourceTypeEnum.HOUSEHOLD.getPersonSourceType());
        invoiceDto.setInvoiceContent(invoiceContent);
        invoiceDto.setPersonId(currentHousehold.getId());
        invoiceDto.setPersonName(currentHousehold.getName());
        invoiceDto.setInvoiceAmount(billTotal);
        invoiceDto.setStatus(InvoiceConstants.InvoiceStatus.TO_BE_INVOICE.getType());
        invoiceDto.setInvoiceType(InvoiceConstants.InvoiceType.ELECTRONIC.getType());
        invoiceDto.setInvoiceNature(InvoiceConstants.InvoiceNature.PLAIN.getType());
        invoiceDto.setInvoiceTitle(invoiceTitleDto);
        invoiceDto.setCreateTime(new Date());

        try {
            // 开票申请信息保存
            invoiceService.submitInvoiceApply(invoiceDto, invoiceItemList);
            // todo 调用开票接口

        } catch (Exception e) {
            throw new CheckErrorException(e);
        }

        return Response.ok().wrap("开票信息提交完成");
    }
}
